package com.dongrj.framework.web.redisson;

import com.dongrj.framework.core.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.BatchOptions;
import org.redisson.api.RBatch;
import org.redisson.api.RBucket;
import org.redisson.api.RBuckets;
import org.redisson.client.codec.StringCodec;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Function;

@Slf4j
public final class RedissonUtils {
    /**
     * 默认缓存时间(7天)
     */
    private static final Long DEFAULT_EXPIRED = 604800L;


    /**
     * 移除缓存
     *
     * @param key 键
     */
    public static void delete(String key) {
        log.info("delete.key={}", key);
        CustomRedisson.getInstance().getBucket(key).delete();
    }


    /**
     * 读取缓存中的字符串，永久有效
     *
     * @param key 缓存key
     * @return 字符串
     */
    public static String getStr(String key) {
        return get(key, String.class, null);
    }

    /**
     * key是否存在
     *
     * @param key 键
     */
    public static boolean exists(String key) {
        RBucket<Object> bucket = CustomRedisson.getInstance().getBucket(key);
        return bucket.isExists();
    }


    public static <T> T get(String key, Class<T> tClass) {
        return get(key, tClass, null);
    }

    public static <T> List<T> getList(String key, Class<T> tClass) {
        return getList(key, tClass, new ArrayList<>());
    }

    public static <T> List<T> getList(String key, Class<T> tClass, List<T> dfValue) {
        RBucket<String> bucket = CustomRedisson.getInstance().getBucket(key);
        String value = bucket.get();
        List<T> ts = JsonUtils.toList(value, tClass);
        if (ts == null) {
            return dfValue;
        }
        return ts;
    }

    /**
     * 缓存字符串
     *
     * @param key   键
     * @param value 值
     */
    public static void setStr(String key, String value) {
        set(key, value);
    }

    public static void set(String key, Object value) {
        set(key, value, 0);
    }

    /**
     * 缓存带过期时间的字符串
     *
     * @param key     缓存key
     * @param value   缓存值
     * @param expired 缓存过期时间，long类型，必须传值
     */
    public static void set(String key, Object value, long expired) {
        RBucket<String> bucket = CustomRedisson.getInstance().getBucket(key, StringCodec.INSTANCE);
        bucket.set(JsonUtils.toJson(value), expired <= 0L ? DEFAULT_EXPIRED : expired, TimeUnit.SECONDS);
    }

    /**
     * 判断缓存是否存在
     *
     * @param key 键
     * @return true 存在
     */
    public static Boolean isExists(String key) {
        return CustomRedisson.getInstance().getBucket(key).isExists();
    }

    /**
     * 批量获取值
     *
     * @param keys 键集合
     */
    public static Map<String, Object> batchBucketGet(String... keys) {
        RBuckets buckets = CustomRedisson.getInstance().getBuckets();
        return buckets.get(keys);
    }

    public static void batchBucketSet(Map<String, String> map) {
        RBuckets buckets = CustomRedisson.getInstance().getBuckets();
        buckets.set(map);
    }

    public static void batchBucketSet(Map<String, String> map, long expiredSecond) {
        long expireTime = expiredSecond <= 0L ? DEFAULT_EXPIRED : expiredSecond;
        RBatch batch = CustomRedisson.getInstance().createBatch();
        map.forEach(new BiConsumer<String, String>() {
            public void accept(String key, String value) {
                batch.getBucket(key).setAsync(value, expireTime, TimeUnit.SECONDS);
            }
        });
        batch.execute();
    }

    public static void mapPut(String mapKey, String key, String value) {
        RBatch batch = CustomRedisson.getInstance().createBatch(BatchOptions.defaults());
        batch.getMap(mapKey).fastPutAsync(key, value);
        batch.execute();
    }

    public static <T, P> T get(String key, Class<T> tClass, T dfValue) {
        Function<P, T> ss = (p) -> dfValue;
        return getIfAbsent(key, tClass, null, ss);
    }


    public static <T, P> T getIfAbsent(String key, Class<T> tClass, P p, Function<P, T> function) {
        if (tClass.equals(String.class)) {
            RBucket<T> bucket = CustomRedisson.getInstance().getBucket(key);
            return bucket.get();
        }
        RBucket<String> bucket = CustomRedisson.getInstance().getBucket(key);
        String value = bucket.get();
        T t = JsonUtils.toBean(value, tClass);
        if (t == null) {
            log.warn("{},null", key);
            T apply = function.apply(p);
            if (Objects.nonNull(apply)) {
                set(key, apply);
                return apply;
            } else {
                // TODO 填充
                log.info("getIfAbsent.param={}", p);
            }
        }
        return t;
    }
}